﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Tools;
using System.Data;
using System.Windows.Forms;

namespace JHStock
{
    public class TestStocks
    {
        private JHConfig _jhconfig;
        private StocksData stocksData;

        public List<Stock> selectstock { get; set; }
        public List<string> savestockinfor { get; set; } //与selectstock 同步

        private bool _FromParentCmd;
        private string _ParentMsg;
        private string kdataType { get { return stocksData.KdataType; } }
        public TestStocks(JHConfig _jhconfig, StocksData stocksData)
        {
            // TODO: Complete member initialization
            this._jhconfig = _jhconfig;
            this.stocksData = stocksData;
            selectstock = new List<Stock>();
            savestockinfor = new List<string>();
        }
        public string TestStockSelect(Stock s, bool ComputeVol, bool bCrossKdata,bool bMonitOnedays=false,
            bool DebugOutPut = false, int staticdaylenght = 200, bool FromParentCmd = false, int daylydays = 0,bool OutLS = false)
        {
            _FromParentCmd = FromParentCmd;
            _ParentMsg = "";
            if (ComputeVol)
            {
                if (OutLS){
                    _ParentMsg = "_MonitOneDay_"+bMonitOnedays + "_debug_"+DebugOutPut+"_days_"+staticdaylenght;
                }
                else
                    TestStock(s, ComputeVol,bMonitOnedays, DebugOutPut, staticdaylenght);
            }
            else
            {
                int L = 10;
                int S = 5;
                if (kdataType == "dayly")
                {
                    S = 10;
                    L = 20;
                    if (bCrossKdata && daylydays >= 10)
                        L = daylydays;
                }
                else if (kdataType == "weekly") //20,40
                {
                    S = 20;
                    L = 40;
                }
                else if (kdataType == "monthly") //5,10
                {
                    S = 5;
                    L = 10;
                }
                if (OutLS)
                {
                    _ParentMsg = "_L=" + L + "_S=" + S;
                    if (bCrossKdata)
                        _ParentMsg = "Price_CrossKdata_L=" + L + "_S=" + S;
                }
                else
                    TestStockMA(s, S, L, ComputeVol, bCrossKdata, DebugOutPut, staticdaylenght);
            }
            if (FromParentCmd)
                return _ParentMsg;
            return "";
        }
        public void TestStock(Stock s, bool ComputeVol,bool monitoneday=false,  bool DebugOutPut = false, int staticdaylenght = 200)
        {
            if (!stocksData.HasLocalKdata(s.ID))
                return;
            double[] kdvol;
            if (ComputeVol)
                kdvol = stocksData.GetLocalKD(s.ID).Select(r => (double)(r.vol)).ToArray();
            else
                kdvol = stocksData.GetLocalKD(s.ID).Select(r => (double)(r.close)).ToArray();
            if (staticdaylenght != 200 && staticdaylenght > kdvol.Length && stocksData.Inline)
            {
                // TODO: Complete TestStock
                LocalKdTagstock lt = ThreadUpdateStocksQQDayly.DownLoadData(s, staticdaylenght);
                if (ComputeVol)
                    kdvol = lt.Akd.Select(r => (double)(r.vol)).ToArray();
                else
                    kdvol = lt.Akd.Select(r => (double)(r.close)).ToArray();
            }


            List<double> vma5 = MA(0, 5, kdvol);
            double now = vma5[0];
            List<double> dvma5rate = vma5.Select(r =>
            { double ret = (r - now) / now; now = r; return ret; }).ToList();
            List<int> ma5L = dvma5rate.Select(r => (int)(r * 100 + (r > 0 ? 0.5 : -0.5))).ToList();
            //List<double> vdvma5rate = MA(0, 5, dvma5rate.ToArray());
            //List<int> intvdvma5rate = vdvma5rate.Select(r => (int)(r * 100 * 5 + (r > 0 ? 0.5 : -0.5))).ToList();
            List<Point> lines =
                HorizontalLines(ma5L, 18, 15, 12);  //firstbigbreak,secondbigbreak,thirdbigbreak
            lines = MergeLines(lines, ma5L, 24); //合并条件1. 两条线只差一点 2.该点数值在  24  以内  //以后再优化
            if (lines.Count > 0)
            {
                Point LastLine = lines[lines.Count - 1];
                int epos = LastLine.X + LastLine.Y;
                int undays = ma5L.Count - epos;


                if ((!monitoneday && undays < 5 && undays > 2 && Math.Abs(ma5L[epos + 1]) > 29 && Math.Abs(ma5L[epos + 2]) > 29)  //监视两天
                   || (monitoneday && undays < 5 && undays > 1 && Math.Abs(ma5L[epos + 1]) > 29))//一天为监视
                {
                    selectstock.Add(s);
                    // 持续天数  \t 后续天数  \t  后续天数的情况
                    savestockinfor.Add(LastLine.Y + "\t" + undays + "\t" + string.Join(",", ma5L.Skip(epos).Take(undays)));
                }
            }
            if (_FromParentCmd)
            {
                List<int> L = ma5L.Select(r => 0).ToList();
                string str = string.Join(",", L.Select(r => r.ToString()).ToList());
                _ParentMsg = s.Name + "\t" + s.NumCode + "\tL:" + str;
            }
            if (DebugOutPut)
            {
                List<int> L = ma5L.Select(r => 0).ToList();
                foreach (Point p in lines)
                    for (int i = 0; i < p.Y; i++)
                        L[i + p.X] = 1;

                int li = 0; //数组长度需一致
                List<List<string>> lls = vma5.Select(r => { List<string> re = new List<string> { r.ToString(), ma5L[li].ToString(), L[li].ToString() }; li++; return re; }).ToList();

                string str = "\r\nvma5\tma5L\tL\r\n" + lls.Select(r => string.Join("\t", r)).Aggregate((r1, r2) => r1 + "\r\n" + r2);
                MFile.WriteAllText(this._jhconfig.Jsconfig.pathconfig.NowWorkPath() + kdataType + "_debugCompute_Vol" + ComputeVol + s.Name + s.NumCode + ".txt", str);
            }
        }
        private void TestStockMA(Stock s, int S, int L, bool ComputeVol, bool bCrossKdata, bool DebugOutPut = false, int staticdaylenght = 200)
        {
            if (!stocksData.HasLocalKdata(s.ID))
                return;
            List<KData> kd = stocksData.GetLocalKD(s.ID);
            if (staticdaylenght != 200 && staticdaylenght > kd.Count && stocksData.Inline)
            {
                LocalKdTagstock lt = ThreadUpdateStocksQQDayly.DownLoadData(s, staticdaylenght);
                kd = lt.Akd;
            }
            double[] kdvol;
            if (ComputeVol)
                kdvol = kd.Select(r => (double)(r.vol)).ToArray();
            else
                kdvol = kd.Select(r => (double)(r.close / 100.0)).ToArray();

            List<double> maL = MA(0, L, kdvol);
            List<double> maS = new List<double>();
            if (bCrossKdata)
            {
                maS = kd.Skip(L - 1).Select(r => (Double)(Math.Max(r.close, r.open) / 100.0)).ToList();
            }
            else
            {
                maS = MA(L - S, S, kdvol);
            }

            List<double> Bar = new List<double>();
            for (int i = 0; i < maL.Count; i++)
                Bar.Add(maS[i] - maL[i]);
            double max = Bar.Max(r => Math.Abs(r));
            //百分
            List<int> PerBar = Bar.Select(r => (int)(r * 100 / max + (r > 0 ? 0.5 : -0.5))).ToList();
            PerBar.Reverse();
            int N = 0;
            int P = 0;
            if (PerBar[0] >= 0)
            {
                N = PerBar.FindIndex(r => r < 0);
                if (N >= 0)
                {
                    P = PerBar.FindIndex(N, r => r >= 0);
                    P -= N;
                    //N -= 1;
                }
            }
            if (N >= 0 && P > 0)
            {
                bool bselect = false;
                if (kdataType == "dayly" && N <= 2 && P >= 10
                    || kdataType == "weekly" && N <= 1 && P >= 10
                    || kdataType == "monthly" && N <= 1 && P >= 8)
                {
                    bselect = true;
                }
                if (bselect)
                {
                    selectstock.Add(s);
                    // 持续天数  \t 后续天数  \t  后续天数的情况
                    PerBar.Reverse();
                    List<int> LL = PerBar.Take(N).ToList();
                    savestockinfor.Add(P + "\t" + N + "\t" + string.Join(",", LL));
                }
            }
            if (_FromParentCmd)
            {
                int skip = 0;
                if (N >= 0 && P > 0)
                    skip = Bar.Count - N - P - 1;
                string str = string.Join(",", Bar.Skip(skip).Select(r => r.ToString("0.000")).ToList());
                _ParentMsg = s.Name + "\t'" + s.NumCode + "\t" + P + "\t" + N + "\tBar\t" + str;
            }
            if (DebugOutPut)
            {
                int li = 0;
                List<List<string>> lls = maL.Select(r =>
                {
                    List<string> re = new List<string> { kd[li + L - 1].date.ToString(), r.ToString("0.00"), maS[li].ToString("0.00"), Bar[li].ToString("0.000") }; li++; return re;
                }).ToList();
                string str = "\r\nDate\tmaL\tmaS\tBar\r\n" + lls.Select(r => string.Join("\t", r)).Aggregate((r1, r2) => r1 + "\r\n" + r2);

                MFile.WriteAllText(this._jhconfig.Jsconfig.pathconfig.NowWorkPath() + kdataType + " " + P + "-" + N + "_debugCompute_Vol" + ComputeVol + s.Name + s.NumCode + ".txt", str);
            }
        }
        private List<Point> MergeLines(List<Point> lines, List<int> maL, int bigbreak)
        {
            if (lines.Count < 2) return lines; ;
            List<Point> nlines = new List<Point>();
            Point L = lines[0];
            for (int i = 1; i < lines.Count; i++)
            {
                if (L.X + L.Y + 1 != lines[i].X || maL[lines[i].X - 1] > bigbreak)
                {
                    nlines.Add(L);
                    L = lines[i];
                }
                else
                {
                    L.Y += 1 + lines[i].Y;
                }
            }
            if (!nlines.Contains(L))
                nlines.Add(L);
            return nlines;
        }
        private List<Point> HorizontalLines(List<int> data, int firstbigbreak, int secondbigbreak, int thirdbigbreak)
        {

            Point line = new Point(0, 0);
            int fc = 0, sc = 0, tc = 0, lc = 0;
            List<Point> Lines = new List<Point>(); // Size.X  StartPoint  Size.Y  lenght
            List<int> absdata = data.Select(r => Math.Abs(r)).ToList();
            if (absdata[0] <= firstbigbreak)
                lc++;
            for (int i = 0; i < absdata.Count; i++)
            {
                if (absdata[i] > firstbigbreak)
                    fc++;
                else if (absdata[i] > secondbigbreak)
                    sc++;
                else if (absdata[i] > thirdbigbreak)
                    tc++;

                if (lc == 1 && i - line.X > 5)
                {
                    if (absdata[i - 5] > firstbigbreak)
                    {
                        if (fc > 0) fc--;
                    }
                    else if (absdata[i - 5] > secondbigbreak)
                    {
                        if (sc > 0) sc--;
                    }
                    else if (absdata[i - 5] > thirdbigbreak)
                    {
                        if (tc > 0) tc--;
                    }
                }


                if (fc == 1 || sc == 2 || tc == 3 || sc + tc == 3)  //bbreak = true;
                {
                    fc = sc = tc = 0;

                    if (lc == 1)  // lc == 2  //lineend //五天以上
                    {
                        lc = 0;
                        line.Y = i - line.X;
                        if (line.Y > 4)
                            Lines.Add(line);
                    }
                }
                else
                {
                    if (lc == 0) // line 未开始状态
                    {
                        lc++;
                        line.X = i;
                    }
                }

            }
            return Lines;
        }
        private double maxsublinear(List<double> a, out int b, out int e)
        {
            int i;
            int begin = 0, end = 0, lbegin = 0;
            double curSum = 0; ///* 当前序列和 //
            double maxSum = 0; ///* 最大序列和 //

            ////* 开始循环求子序列和
            for (i = 0; i < a.Count; i++)
            {
                curSum = curSum + a[i];

                ///* 与最大子序列和比较，更新最大子序列和 /
                if (curSum > maxSum)
                {
                    maxSum = curSum;
                    end = i;
                    if (begin < end)
                        lbegin = begin;
                    else
                        lbegin = lbegin + 0;
                }

                ///* 动态规划部分，舍弃当前和为负的子序列 /
                if (curSum < 0)
                {
                    curSum = 0;
                    begin = i + 1 >= a.Count ? i : i + 1;

                }
            }
            b = lbegin;
            e = end;
            return maxSum;
        }
        //type = 0: close  type = 1: vol type =  2: open type=3 high  type=4 low
        private List<double> MA(int skip, int daylength, int[] listdata)
        {
            List<double> MA = new List<double>();
            listdata = listdata.Skip(skip).ToArray();
            double sum = listdata.Take(daylength).Sum();
            skip = 0;
            for (int i = skip + daylength; i < listdata.Length; i++)
            {
                double avg = sum * 1.0 / daylength;
                MA.Add(avg);
                sum += listdata[i] - listdata[i - daylength];
            }
            MA.Add(sum * 1.0 / daylength);
            return MA;
        }
        public static List<double> MA(int skip, int daylength, double[] listdata)
        {
            List<double> MA = new List<double>();
            listdata = listdata.Skip(skip).ToArray();
            double sum = listdata.Take(daylength).Sum();
            skip = 0;
            for (int i = skip + daylength; i < listdata.Length; i++)
            {
                double avg = sum * 1.0 / daylength;
                MA.Add(avg);
                sum += listdata[i] - listdata[i - daylength];
            }
            MA.Add(sum * 1.0 / daylength);
            return MA;
        }       

        //////////
        public static DataTable CreateMonitDataTable()
        {
            DataTable dt = new DataTable();
            List<string> columntitles = new List<string>() { "名称", "代码", "持续天数", "后续天数", "后续天数的情况", "画图", "分时图", "财务信息", "选择" };//   "日期",
            //columntitles = new List<string>() { "名称", "代码","杂项" };//,"杂项"
            for (int count = 0; count < columntitles.Count; count++)
            {
                DataColumn dc = new DataColumn(columntitles[count]);
                if ("代码名称状态杂项日期".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(string);
                }
                else if ("上一状态持续天数后续天数".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(int);
                }
                else if ("画图分时图".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(Image);
                }
                else if ("选择".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(Boolean);
                }
                else
                {
                    dc.DataType = typeof(string);
                    //dc.MaxLength = 30;
                }
                dt.Columns.Add(dc);
            }
            return dt;
        }
        public static void InitDgvUI(DataTable dt, DataGridView dgv)
        {
            dgv.DataSource = dt; // 宽度应设置在 dgv 上

            for (int i = 0; i < dgv.ColumnCount; i++)
            {
                if ("代码名称状态杂项日期".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 60;
                }
                else if ("上一状态持续天数后续天数".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 40;
                }
                else if ("画图分时图".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 200;
                    dgv.Columns[i].CellTemplate.Style.BackColor = Color.Black;
                }
                else if ("财务信息".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 200;
                }
                else if ("选择".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].CellTemplate.Style.BackColor = Color.Gray;
                }
                else
                {
                    dgv.Columns[i].Width = 120;
                    //dc.MaxLength = 30;
                }
            }
            dgv.RowTemplate.Height = 100;
        }
        public static DataTable CreateShowStockDataTable()
        {
            DataTable dt = new DataTable();
            List<string> columntitles = new List<string>() { "ID", "名称", "画图" };
            //new List<string>() { "名称", "代码", "持续天数", "后续天数", "后续天数的情况", "画图", "分时图", "财务信息", "选择" };//   "日期",
            //columntitles = new List<string>() { "名称", "代码","杂项" };//,"杂项"
            for (int count = 0; count < columntitles.Count; count++)
            {
                DataColumn dc = new DataColumn(columntitles[count]);
                if ("代码名称状态杂项日期".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(string);
                }
                else if ("ID上一状态持续天数后续天数".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(int);
                }
                else if ("画图分时图".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(Image);
                }
                else if ("选择".Contains(columntitles[count]))
                {
                    dc.DataType = typeof(Boolean);
                }
                else
                {
                    dc.DataType = typeof(string);
                    //dc.MaxLength = 30;
                }
                dt.Columns.Add(dc);
            }
            return dt;
        }
        public static void InitShowStockDgvUI(DataTable dt, DataGridView dgv)
        {
            dgv.DataSource = dt; // 宽度应设置在 dgv 上

            for (int i = 0; i < dgv.ColumnCount; i++)
            {
                if ("代码名称状态杂项日期".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 60;
                }
                else if ("上一状态持续天数后续天数".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 40;
                }
                else if ("画图分时图".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 450;
                    dgv.Columns[i].CellTemplate.Style.BackColor = Color.Black;
                }
                else if ("财务信息".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 200;
                }
                else if ("选择".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].CellTemplate.Style.BackColor = Color.Gray;
                }
                else if ("ID".Contains(dgv.Columns[i].Name))
                {
                    dgv.Columns[i].Width = 0;
                    //dc.MaxLength = 30;
                }
                else
                {
                    dgv.Columns[i].Width = 120;
                    //dc.MaxLength = 30;
                }
            }
            dgv.RowTemplate.Height =300;
            foreach (DataGridViewColumn dc in dgv.Columns)
                if (dc.Name.Contains("画图"))
                    ((DataGridViewImageColumn)(dc)).ImageLayout = DataGridViewImageCellLayout.Zoom;
        }
    }
}
